1 : <?php
2 : /**
3 : * Container implementation.
4 : *
5 : * PHP Version 5
6 : *
7 : * @category Ding
8 : * @package Container
9 : * @subpackage Impl
10 : * @author Marcelo Gornstein <marcelog@gmail.com>
11 : * @license http://marcelog.github.com/ Apache License 2.0
12 : * @link http://marcelog.github.com/
13 : *
14 : * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
15 : *
16 : * Licensed under the Apache License, Version 2.0 (the "License");
17 : * you may not use this file except in compliance with the License.
18 : * You may obtain a copy of the License at
19 : *
20 : * http://www.apache.org/licenses/LICENSE-2.0
21 : *
22 : * Unless required by applicable law or agreed to in writing, software
23 : * distributed under the License is distributed on an "AS IS" BASIS,
24 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 : * See the License for the specific language governing permissions and
26 : * limitations under the License.
27 : *
28 : */
29 : namespace Ding\Container\Impl;
30 :
31 : use Ding\Helpers\ErrorHandler\ErrorInfo;
32 :
33 : use Ding\Bean\IBeanDefinitionProvider;
34 : use Ding\Cache\Impl\DummyCacheImpl;
35 : use Ding\Bean\Provider\Core;
36 : use Ding\Resource\Impl\IncludePathResource;
37 : use Ding\Resource\Impl\FilesystemResource;
38 : use Ding\Resource\Impl\URLResource;
39 : use Ding\Cache\Locator\CacheLocator;
40 : use Ding\Container\IContainer;
41 : use Ding\Aspect\AspectManager;
42 : use Ding\Aspect\InterceptorDefinition;
43 : use Ding\Aspect\AspectDefinition;
44 : use Ding\Aspect\Interceptor\IDispatcher;
45 : use Ding\Aspect\Interceptor\DispatcherImpl;
46 : use Ding\Reflection\ReflectionFactory;
47 : use Ding\Bean\Lifecycle\BeanLifecycle;
48 : use Ding\Bean\Lifecycle\BeanLifecycleManager;
49 : use Ding\Bean\Factory\Exception\BeanFactoryException;
50 : use Ding\Bean\BeanConstructorArgumentDefinition;
51 : use Ding\Bean\BeanDefinition;
52 : use Ding\Bean\BeanPropertyDefinition;
53 : use Ding\MessageSource\IMessageSource;
54 :
55 : /**
56 : * Container implementation.
57 : *
58 : * PHP Version 5
59 : *
60 : * @category Ding
61 : * @package Container
62 : * @subpackage Impl
63 : * @author Marcelo Gornstein <marcelog@gmail.com>
64 : * @license http://marcelog.github.com/ Apache License 2.0
65 : * @link http://marcelog.github.com/
66 : */
67 : class ContainerImpl implements IContainer
68 : {
69 : /**
70 : * Signals to handle.
71 : * @var array
72 : */
73 : private $_signals = array(
74 : SIGQUIT, SIGHUP, SIGINT, SIGCHLD, SIGTERM, SIGUSR1, SIGUSR2
75 : );
76 : /**
77 : * Logger.
78 : * @var Logger
79 : */
80 : private $_logger;
81 :
82 : /**
83 : * Cache for isDebugEnabled()
84 : * @var boolean
85 : */
86 : private $_logDebugEnabled;
87 :
88 : /**
89 : * Dispatcher to be cloned for proxy.
90 : * @var DispatcherImpl
91 : */
92 : private $_dispatcherTemplate = null;
93 :
94 : /**
95 : * MessageSource implementation.
96 : * @var IMessageSource
97 : */
98 : private $_messageSource = false;
99 : /**
100 : * Default options.
101 : * @var array
102 : */
103 : private static $_options = array(
104 : 'bdef' => array(),
105 : 'properties' => array(),
106 : 'drivers' => array()
107 : );
108 :
109 : /**
110 : * Registered shutdown methods for beans (destroy-methods).
111 : * @var array
112 : */
113 : private $_shutdowners = array();
114 :
115 : /**
116 : * Beans already instantiated.
117 : * @var object[]
118 : */
119 : private $_beans;
120 :
121 : /**
122 : * Holds our beans cache.
123 : * @var ICache
124 : */
125 : private $_beanCache;
126 :
127 : /**
128 : * Beans already instantiated.
129 : * @var BeanDefinition[]
130 : */
131 : private $_beanDefs;
132 :
133 : /**
134 : * Beans aliases.
135 : * @var string[]
136 : */
137 : private $_beanAliases;
138 :
139 : /**
140 : * Holds our bean definitions cache.
141 : * @var ICache
142 : */
143 : private $_beanDefCache;
144 :
145 : /**
146 : * Container instance.
147 : * @var ContainerImpl
148 : */
149 : private static $_containerInstance = false;
150 :
151 : /**
152 : * The aspect manager.
153 : * @var AspectManager
154 : */
155 : private $_aspectManager = null;
156 :
157 : /**
158 : * The lifecycle manager.
159 : * @var BeanLifecycleManager
160 : */
161 : private $_lifecycleManager = null;
162 :
163 : /**
164 : * Resources multiton.
165 : * @var IResource[]
166 : */
167 : private $_resources = false;
168 :
169 : /**
170 : * The event listeners
171 : * @var string[]
172 : */
173 : private $_eventListeners = false;
174 :
175 : /**
176 : * Bean Definition providers.
177 : * @var IBeanDefinitionProvider[]
178 : */
179 : private $_beanDefinitionProviders = array();
180 :
181 : /**
182 : * The last error message is saved, just to avoid logging repeated messages.
183 : * @var string
184 : */
185 : private $_lastErrorMessage;
186 :
187 : /**
188 : * A ReflectionFactory implementation
189 : * @var IReflectionFactory
190 : */
191 : private $_reflectionFactory;
192 :
193 : /**
194 : * A Proxy factory implementation.
195 : * @var Proxy
196 : */
197 : private $_proxyFactory;
198 :
199 : /**
200 : * Properties configured when instantiating the container and by others,
201 : * like when using a PropertiesHolder.
202 : *
203 : * @var string[]
204 : */
205 : private $_properties;
206 :
207 : /**
208 : * Prevent serialization.
209 : *
210 : * @return array
211 : */
212 : public function __sleep()
213 : {
214 1 : return array('_aspectManager', '_lifecycleManager');
215 : }
216 :
217 : /**
218 : * (non-PHPdoc)
219 : * @see Ding\Bean.IBeanDefinitionProvider::getBeanDefinitionByClass()
220 : */
221 : public function getBeanDefinitionByClass($class)
222 : {
223 3 : foreach ($this->_beanDefinitionProviders as $provider) {
224 3 : $beanDefinition = $provider->getBeanDefinitionByClass($class);
225 3 : }
226 3 : }
227 : /**
228 : * Returns a bean definition.
229 : *
230 : * @param string $name Bean name.
231 : *
232 : * @return BeanDefinition
233 : * @throws BeanFactoryException
234 : */
235 : public function getBeanDefinition($name)
236 : {
237 277 : if (isset($this->_beanAliases[$name])) {
238 2 : $name = $this->_beanAliases[$name];
239 2 : }
240 277 : if (isset($this->_beanDefs[$name])) {
241 181 : return $this->_beanDefs[$name];
242 : }
243 277 : $beanDefinition = null;
244 277 : if ($this->_beanDefCache !== null) {
245 277 : $beanDefinition = $this->_beanDefCache->fetch($name, $result);
246 277 : }
247 277 : if ($beanDefinition) {
248 31 : $this->_beanDefs[$name] = $beanDefinition;
249 31 : return $beanDefinition;
250 : }
251 277 : foreach ($this->_beanDefinitionProviders as $provider) {
252 277 : $beanDefinition = $provider->getBeanDefinition($name);
253 277 : if ($beanDefinition) {
254 277 : $beanDefinition->setClass($this->_searchAndReplaceProperties(
255 277 : $beanDefinition->getClass()
256 277 : ));
257 277 : break;
258 : }
259 277 : }
260 277 : if (!$beanDefinition) {
261 259 : throw new BeanFactoryException('Unknown bean: ' . $name);
262 : }
263 277 : $beanDefinition = $this->_lifecycleManager->afterDefinition($beanDefinition);
264 277 : $this->_beanDefs[$name] = $beanDefinition;
265 277 : $this->_beanDefCache->store($name, $beanDefinition);
266 277 : foreach ($beanDefinition->getAliases() as $alias) {
267 19 : $this->_beanAliases[$alias] = $name;
268 277 : }
269 277 : return $beanDefinition;
270 : }
271 :
272 : /**
273 : * Will try to search and replace the properties found in the given
274 : * value.
275 : *
276 : * @param string $value
277 : *
278 : * @return string
279 : */
280 : private function _searchAndReplaceProperties($value)
281 : {
282 277 : if (is_string($value)) {
283 277 : foreach ($this->_properties as $k => $v) {
284 49 : if (strpos($value, $k) !== false) {
285 19 : if (is_string($v)) {
286 19 : $value = str_replace($k, $v, $value);
287 19 : } else {
288 12 : $value = $v;
289 : // Assigned value is not a string, so we cant use
290 : // strpos anymore on it (i.e: cant continue replacing)
291 12 : break;
292 : }
293 19 : }
294 277 : }
295 277 : }
296 277 : return $value;
297 : }
298 :
299 : /**
300 : * Takes care of transforming a scalar value for a property or constructor
301 : * argument, into a an actual value (i.e: if its a resource://, loading it
302 : * first).
303 : *
304 : * @param mixed $value The value
305 : *
306 : * @return mixed
307 : */
308 : private function _loadValue($value)
309 : {
310 277 : $value = $this->_searchAndReplaceProperties($value);
311 277 : if (is_string($value) && strpos($value, 'resource://') === 0) {
312 2 : $value = substr($value, 11);
313 2 : return $this->getResource($value);
314 : }
315 277 : return $value;
316 : }
317 :
318 : /**
319 : * This will resolve a property (or constructor arg) definition to a final
320 : * value, being a bean reference, array of other properties (or
321 : * constructor args), etc.
322 : *
323 : * @param BeanPropertyDefinition|BeanConstructorArgumentDefinition $what
324 : *
325 : * @return void
326 : */
327 : private function _getValueFromDefinition($what)
328 : {
329 277 : $value = null;
330 277 : if ($what->isBean()) {
331 277 : $value = $this->getBean($what->getValue());
332 277 : } else if ($what->isArray()) {
333 53 : $value = array();
334 53 : foreach ($what->getValue() as $k => $v) {
335 53 : $value[$k] = $this->_getValueFromDefinition($v);
336 53 : }
337 277 : } else if ($what->isCode()) {
338 24 : $value = eval($what->getValue());
339 24 : } else {
340 277 : $value = $this->_loadValue($what->getValue());
341 : }
342 277 : return $value;
343 : }
344 :
345 : /**
346 : * Resolves all values for constructor arguments definitions in a
347 : * bean definition.
348 : *
349 : * @param BeanDefinition $definition
350 : *
351 : * @return object
352 : */
353 : private function _getConstructorValuesForDefinition($definition)
354 : {
355 277 : $args = array();
356 277 : foreach ($definition->getArguments() as $argument) {
357 277 : $value = $this->_getValueFromDefinition($argument);
358 277 : if ($argument->hasName()) {
359 4 : $name = $argument->getName();
360 4 : $args[$name] = $value;
361 4 : } else {
362 277 : $args[] = $value;
363 : }
364 277 : }
365 277 : return $args;
366 : }
367 :
368 : /**
369 : * Instantiates a bean using the constructor.
370 : *
371 : * @param BeanDefinition $definition
372 : *
373 : * @return object
374 : */
375 : private function _instantiateByConstructor(BeanDefinition $definition)
376 : {
377 277 : $class = $definition->getClass();
378 277 : if ($definition->hasProxyClass()) {
379 24 : $class = $definition->getProxyClassName();
380 24 : }
381 277 : $rClass = $this->_reflectionFactory->getClass($class);
382 277 : $factoryMethod = $rClass->getConstructor();
383 277 : if ($factoryMethod !== null) {
384 277 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
385 277 : if (empty($args)) {
386 277 : return $rClass->newInstanceArgs();
387 : } else {
388 277 : return $rClass->newInstanceArgs($args);
389 : }
390 : } else {
391 277 : return $rClass->newInstanceArgs();
392 : }
393 : }
394 :
395 : /**
396 : * Instantiates a bean using a factory class.
397 : *
398 : * @param BeanDefinition $definition
399 : *
400 : * @return object
401 : */
402 : private function _instantiateByFactoryClass(BeanDefinition $definition)
403 : {
404 277 : $class = $definition->getClass();
405 277 : $rClass = $this->_reflectionFactory->getClass($class);
406 277 : $factoryMethodName = $definition->getFactoryMethod();
407 277 : $factoryMethod = $rClass->getMethod($factoryMethodName);
408 277 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
409 277 : return forward_static_call_array(array($class, $factoryMethodName), $args);
410 : }
411 :
412 : /**
413 : * Instantiates a bean using a factory bean.
414 : *
415 : * @param BeanDefinition $definition
416 : *
417 : * @return object
418 : */
419 : private function _instantiateByFactoryBean(BeanDefinition $definition)
420 : {
421 70 : $factoryBean = $this->getBean($definition->getFactoryBean());
422 70 : $refObject = new \ReflectionObject($factoryBean);
423 70 : $factoryMethod = $refObject->getMethod($definition->getFactoryMethod());
424 70 : $args = $this->_sortArgsWithNames($definition, $factoryMethod);
425 70 : return $factoryMethod->invokeArgs($factoryBean, $args);
426 : }
427 :
428 : private function _sortArgsWithNames(BeanDefinition $definition, \ReflectionMethod $rMethod)
429 : {
430 277 : $args = $this->_getConstructorValuesForDefinition($definition);
431 277 : $callArgs = array();
432 277 : foreach ($rMethod->getParameters() as $parameter) {
433 277 : $parameterName = $parameter->getName();
434 277 : if (isset($args[$parameterName])) {
435 4 : $callArgs[] = $args[$parameterName];
436 4 : unset($args[$parameterName]);
437 4 : }
438 277 : }
439 277 : foreach ($args as $value) {
440 277 : $callArgs[] = $value;
441 277 : }
442 277 : return $callArgs;
443 : }
444 :
445 : /**
446 : * Instantiates a bean.
447 : *
448 : * @param BeanDefinition $definition
449 : *
450 : * @return object
451 : */
452 : private function _instantiate(BeanDefinition $definition)
453 : {
454 277 : if ($definition->isCreatedByConstructor()) {
455 277 : return $this->_instantiateByConstructor($definition);
456 277 : } else if ($definition->isCreatedWithFactoryBean()) {
457 70 : return $this->_instantiateByFactoryBean($definition);
458 : } else {
459 277 : return $this->_instantiateByFactoryClass($definition);
460 : }
461 : }
462 :
463 : /**
464 : * Creates whatever beans this definition depends on.
465 : *
466 : * @return void
467 : */
468 : private function _createBeanDependencies(BeanDefinition $definition)
469 : {
470 277 : foreach ($definition->getDependsOn() as $depBean) {
471 6 : $this->getBean(trim($depBean));
472 277 : }
473 277 : }
474 :
475 : /**
476 : * Will inject into the given dispatcher the necessary information to
477 : * aspects will be run correctly.
478 : *
479 : * @throws BeanFactoryException
480 : * @return void
481 : */
482 : private function _applyAspect(
483 : $targetClass, AspectDefinition $aspectDefinition, IDispatcher $dispatcher
484 : ) {
485 25 : $rClass = $this->_reflectionFactory->getClass($targetClass);
486 25 : $aspect = $this->getBean($aspectDefinition->getBeanName());
487 25 : foreach ($aspectDefinition->getPointcuts() as $pointcutName) {
488 25 : $pointcut = $this->_aspectManager->getPointcut($pointcutName);
489 25 : if ($pointcut === false) {
490 1 : throw new BeanFactoryException('Could not find pointcut: ' . $pointcutName);
491 : }
492 24 : $expression = $pointcut->getExpression();
493 24 : foreach ($rClass->getMethods() as $method) {
494 24 : $methodName = $method->getName();
495 24 : if (preg_match('/' . $expression . '/', $methodName) === 0) {
496 8 : continue;
497 : }
498 : if (
499 24 : $aspectDefinition->getType() == AspectDefinition::ASPECT_METHOD
500 24 : ) {
501 21 : $dispatcher->addMethodInterceptor($methodName, $aspect, $pointcut->getMethod());
502 21 : } else {
503 5 : $dispatcher->addExceptionInterceptor($methodName, $aspect, $pointcut->getMethod());
504 : }
505 24 : }
506 24 : }
507 24 : }
508 :
509 : /**
510 : * Applies all aspects specifically defined for this bean definition.
511 : *
512 : * @param BeanDefinition $definition
513 : * @param IDispatcher $dispatcher
514 : *
515 : * @return void
516 : */
517 : private function _applySpecificAspects(BeanDefinition $definition, IDispatcher $dispatcher)
518 : {
519 277 : if ($definition->hasAspects()) {
520 17 : foreach ($definition->getAspects() as $aspect) {
521 17 : $this->_applyAspect($definition->getClass(), $aspect, $dispatcher);
522 17 : }
523 17 : }
524 277 : }
525 :
526 : /**
527 : * Looks for any global aspects that may apply to this bean and applies them.
528 : *
529 : * @param BeanDefinition $definition
530 : * @param IDispatcher $dispatcher
531 : *
532 : * @return void
533 : */
534 : private function _applyGlobalAspects(BeanDefinition $definition, IDispatcher $dispatcher)
535 : {
536 277 : $class = $definition->getClass();
537 277 : $rClass = $this->_reflectionFactory->getClass($class);
538 277 : foreach ($this->_aspectManager->getAspects() as $aspect) {
539 29 : $expression = $aspect->getExpression();
540 29 : if (preg_match('/' . $expression . '/', $class) === 0) {
541 29 : $parentClass = $rClass->getParentClass();
542 29 : while($parentClass !== false) {
543 1 : if (preg_match('/' . $expression . '/', $parentClass->getName()) > 0) {
544 1 : $this->_applyAspect($class, $aspect, $dispatcher);
545 1 : }
546 1 : $parentClass = $parentClass->getParentClass();
547 1 : }
548 29 : } else {
549 7 : $this->_applyAspect($class, $aspect, $dispatcher);
550 : }
551 277 : }
552 277 : }
553 :
554 : /**
555 : * Applies specific bean aspects and global defined aspects.
556 : *
557 : * @param BeanDefinition $definition
558 : *
559 : * @return void
560 : */
561 : private function _applyAspects(BeanDefinition $definition)
562 : {
563 277 : $class = $definition->getClass();
564 277 : $dispatcher = clone $this->_dispatcherTemplate;
565 277 : $this->_applySpecificAspects($definition, $dispatcher);
566 277 : $this->_applyGlobalAspects($definition, $dispatcher);
567 277 : if ($dispatcher->hasMethodsIntercepted()) {
568 24 : $definition->setProxyClassName(
569 24 : $this->_proxyFactory->create($class, $dispatcher)
570 24 : );
571 24 : }
572 277 : }
573 : /**
574 : * This will create a new bean, injecting all properties and applying all
575 : * aspects.
576 : *
577 : * @throws BeanFactoryException
578 : * @return object
579 : */
580 : private function _createBean(BeanDefinition $definition)
581 : {
582 277 : $this->_lifecycleManager->beforeCreate($definition);
583 277 : $this->_createBeanDependencies($definition);
584 277 : $this->_applyAspects($definition);
585 277 : $bean = $this->_instantiate($definition);
586 277 : if (!is_object($bean)) {
587 1 : throw new BeanFactoryException(
588 1 : 'Could not instantiate ' . $definition->getName()
589 1 : );
590 : }
591 277 : $this->_assemble($bean, $definition);
592 277 : $this->_setupInitAndShutdown($bean, $definition);
593 277 : $this->_lifecycleManager->afterCreate($bean, $definition);
594 277 : return $bean;
595 : }
596 :
597 : /**
598 : * Calls init method and register shutdown method.
599 : *
600 : * @param object $bean
601 : * @param BeanDefinition $definition
602 : *
603 : * @return void
604 : */
605 : private function _setupInitAndShutdown($bean, BeanDefinition $definition)
606 : {
607 277 : if ($definition->hasInitMethod()) {
608 117 : $initMethod = $definition->getInitMethod();
609 117 : $bean->$initMethod();
610 117 : }
611 277 : if ($definition->hasDestroyMethod()) {
612 32 : $destroyMethod = $definition->getDestroyMethod();
613 32 : $this->registerShutdownMethod($bean, $destroyMethod);
614 32 : }
615 277 : }
616 :
617 : /**
618 : * Tries to inject by looking up set* methods.
619 : *
620 : * @param object $bean
621 : * @param string $name
622 : * @param string $value
623 : *
624 : * @return boolean
625 : */
626 : private function _setterInject($bean, $name, $value)
627 : {
628 277 : $methodName = 'set' . ucfirst($name);
629 277 : $rClass = $this->_reflectionFactory->getClass(get_class($bean));
630 277 : if ($rClass->hasMethod($methodName)) {
631 277 : $bean->$methodName($value);
632 277 : return true;
633 : }
634 18 : return false;
635 : }
636 :
637 : /**
638 : * Tries to inject by looking up a property by name.
639 : *
640 : * @param object $bean
641 : * @param string $name
642 : * @param string $value
643 : *
644 : * @return boolean
645 : */
646 : private function _propertyInject($bean, $name, $value)
647 : {
648 18 : $rClass = $this->_reflectionFactory->getClass(get_class($bean));
649 18 : if ($rClass->hasProperty($name)) {
650 17 : $rProperty = $rClass->getProperty($name);
651 17 : if (!$rProperty->isPublic()) {
652 11 : $rProperty->setAccessible(true);
653 11 : }
654 17 : $rProperty->setValue($bean, $value);
655 17 : return true;
656 : }
657 1 : return false;
658 : }
659 : /**
660 : * Assembles a bean (setter injection)
661 : *
662 : * @param mixed $bean
663 : * @param BeanDefinition $beanDefinition
664 : *
665 : * @return void
666 : */
667 : private function _assemble($bean, BeanDefinition $beanDefinition)
668 : {
669 277 : $this->_lifecycleManager->beforeAssemble($bean, $beanDefinition);
670 277 : foreach ($beanDefinition->getProperties() as $property) {
671 277 : $propertyName = $property->getName();
672 277 : $propertyValue = $this->_getValueFromDefinition($property);
673 : if (
674 277 : $this->_setterInject($bean, $propertyName, $propertyValue)
675 18 : || $this->_propertyInject($bean, $propertyName, $propertyValue)
676 277 : ) {
677 277 : continue;
678 : }
679 1 : throw new BeanFactoryException("Dont know how to inject: $propertyName");
680 277 : }
681 277 : $this->fillAware($beanDefinition, $bean);
682 277 : $this->_lifecycleManager->afterAssemble($bean, $beanDefinition);
683 277 : }
684 : /**
685 : * Returns a bean.
686 : *
687 : * @param string $name Bean name.
688 : *
689 : * @throws BeanFactoryException
690 : * @return object
691 : */
692 : public function getBean($name)
693 : {
694 277 : $ret = false;
695 277 : $beanDefinition = $this->getBeanDefinition($name);
696 277 : $beanName = $name . '.bean';
697 277 : if ($beanDefinition->isAbstract()) {
698 1 : throw new BeanFactoryException(
699 1 : "Cant instantiate abstract bean: $name"
700 1 : );
701 : }
702 277 : if ($beanDefinition->isPrototype()) {
703 38 : $ret = $this->_createBean($beanDefinition);
704 277 : } else if ($beanDefinition->isSingleton()) {
705 277 : if (isset($this->_beans[$beanName])) {
706 176 : $ret = $this->_beans[$beanName];
707 176 : } else {
708 277 : $ret = $this->_beanCache->fetch($beanName, $result);
709 277 : if (!$ret) {
710 277 : $ret = $this->_createBean($beanDefinition);
711 277 : }
712 277 : $this->_beans[$beanName] = $ret;
713 : }
714 277 : }
715 277 : return $ret;
716 : }
717 :
718 : /**
719 : * This will return a container
720 : *
721 : * @param array $properties Container properties.
722 : *
723 : * @return ContainerImpl
724 : */
725 : public static function getInstance(array $properties = array())
726 : {
727 277 : if (self::$_containerInstance === false) {
728 : // Init cache subsystems.
729 277 : if (isset($properties['ding']['cache'])) {
730 158 : CacheLocator::configure($properties['ding']['cache']);
731 158 : }
732 277 : if (isset($properties['ding']['log4php.properties'])) {
733 277 : \Logger::configure($properties['ding']['log4php.properties']);
734 277 : }
735 277 : self::$_containerInstance = new ContainerImpl($properties['ding']['factory']);
736 273 : }
737 273 : return self::$_containerInstance;
738 : }
739 :
740 : /**
741 : * Register a shutdown (destroy-method) method for a bean.
742 : *
743 : * @param object $bean Bean to call.
744 : * @param string $method Method to call.
745 : *
746 : * @see Ding\Container.IContainer::registerShutdownMethod()
747 : *
748 : * @return void
749 : */
750 : public function registerShutdownMethod($bean, $method)
751 : {
752 32 : $this->_shutdowners[] = array($bean, $method);
753 32 : }
754 :
755 : /**
756 : * Destructor, will call all beans destroy-methods.
757 : *
758 : * @return void
759 : */
760 : public function __destruct()
761 : {
762 16 : foreach ($this->_shutdowners as $shutdownCall) {
763 16 : $bean = $shutdownCall[0];
764 16 : $method = $shutdownCall[1];
765 16 : $bean->$method();
766 16 : }
767 16 : }
768 :
769 : /**
770 : *
771 : * Enter description here ...
772 : * @param unknown_type $messageSource
773 : */
774 : public function setMessageSource(IMessageSource $messageSource)
775 : {
776 14 : $this->_messageSource = $messageSource;
777 14 : }
778 :
779 : /**
780 : * (non-PHPdoc)
781 : * @see Ding\MessageSource.IMessageSource::getMessage()
782 : */
783 : public function getMessage($bundle, $message, array $arguments, $locale = 'default')
784 : {
785 : return
786 3 : $this->_messageSource !== false
787 3 : ? $this->_messageSource->getMessage($bundle, $message, $arguments, $locale)
788 3 : : NULL;
789 : }
790 :
791 : /**
792 : * (non-PHPdoc)
793 : * @see Ding\Resource.IResourceLoader::getResource()
794 : */
795 : public function getResource($location, $context = false)
796 : {
797 : // Missing scheme?
798 8 : $scheme = strpos($location, '://');
799 8 : if ($scheme === false) {
800 1 : $location = FilesystemResource::SCHEME . $location;
801 1 : }
802 : // Already served?
803 8 : if (isset($this->_resources[$location])) {
804 1 : return $this->_resources[$location];
805 : }
806 : // See what kind of resource to return.
807 8 : if (strpos($location, FilesystemResource::SCHEME) === 0) {
808 3 : $resource = new FilesystemResource($location, $context);
809 8 : } else if (strpos($location, IncludePathResource::SCHEME) === 0) {
810 4 : $resource = new IncludePathResource($location, $context);
811 4 : } else {
812 1 : $resource = new URLResource($location, $context);
813 : }
814 8 : $this->_resources[$location] = $resource;
815 8 : return $resource;
816 : }
817 :
818 : /**
819 : * (non-PHPdoc)
820 : * @see Ding\Bean.IBeanDefinitionProvider::getBeansListeningOn()
821 : */
822 : public function getBeansListeningOn($eventName)
823 : {
824 14 : if (isset($this->_eventListeners[$eventName])) {
825 1 : return $this->_eventListeners[$eventName];
826 : }
827 13 : return array();
828 : }
829 :
830 : /**
831 : * (non-PHPdoc)
832 : * @see Ding\Container.IContainer::eventDispatch()
833 : */
834 : public function eventDispatch($eventName, $data = null)
835 : {
836 14 : if ($this->_logDebugEnabled) {
837 14 : $this->_logger->debug("Dispatching event: $eventName");
838 14 : }
839 14 : $listeners = $this->getBeansListeningOn($eventName);
840 14 : foreach ($this->_beanDefinitionProviders as $provider) {
841 14 : $listeners = array_merge($listeners, $provider->getBeansListeningOn($eventName));
842 14 : }
843 14 : $eventName = 'on' . ucfirst($eventName);
844 14 : foreach ($listeners as $beanName) {
845 5 : $bean = $this->getBean($beanName);
846 5 : $bean->$eventName($data);
847 14 : }
848 14 : }
849 :
850 : /**
851 : * (non-PHPdoc)
852 : * @see Ding\Container.IContainer::eventListen()
853 : */
854 : public function eventListen($eventName, $beanName)
855 : {
856 1 : if (!isset($this->_eventListeners[$eventName])) {
857 1 : $this->_eventListeners[$eventName] = array();
858 1 : }
859 1 : $this->_eventListeners[$eventName][] = $beanName;
860 1 : }
861 :
862 : /**
863 : * (non-PHPdoc)
864 : * @see Ding\Container.IContainer::registerBeanDefinitionProvider()
865 : */
866 : public function registerBeanDefinitionProvider(IBeanDefinitionProvider $provider)
867 : {
868 277 : $this->_beanDefinitionProviders[] = $provider;
869 277 : }
870 :
871 : /**
872 : * If we dont have a ReflectionFactory yet (i.e: didnt make the call to
873 : * getBean() yet), replace it with this one.
874 : *
875 : * @param string $class The name of a class.
876 : *
877 : * @return ReflectionClass
878 : */
879 : protected function getClass($class)
880 : {
881 277 : return new \ReflectionClass($class);
882 : }
883 :
884 : /**
885 : * Will look for "aware" kind of interfaces and inject whatever necessary.
886 : *
887 : * @param BeanDefinition $def The Bean Definition
888 : * @param object $bean The bean
889 : *
890 : * @return void
891 : */
892 : public function fillAware(BeanDefinition $def, $bean)
893 : {
894 277 : $class = get_class($bean);
895 277 : $rClass = $this->_reflectionFactory->getClass($class);
896 277 : if ($rClass->implementsInterface('Ding\Reflection\IReflectionFactoryAware')) {
897 277 : $bean->setReflectionFactory($this->_reflectionFactory);
898 277 : }
899 277 : if ($rClass->implementsInterface('Ding\Bean\IBeanNameAware')) {
900 1 : $bean->setBeanName($def->getName());
901 1 : }
902 277 : if ($rClass->implementsInterface('Ding\Logger\ILoggerAware')) {
903 198 : $bean->setLogger(\Logger::getLogger($class));
904 198 : }
905 277 : if ($rClass->implementsInterface('Ding\Container\IContainerAware')) {
906 277 : $bean->setContainer($this);
907 277 : }
908 277 : if ($rClass->implementsInterface('Ding\Resource\IResourceLoaderAware')) {
909 277 : $bean->setResourceLoader($this);
910 277 : }
911 277 : if ($rClass->implementsInterface('Ding\Aspect\IAspectManagerAware')) {
912 277 : $bean->setAspectManager($this->_aspectManager);
913 277 : }
914 :
915 277 : if ($rClass->implementsInterface('Ding\Bean\IBeanDefinitionProvider')) {
916 277 : $this->registerBeanDefinitionProvider($bean);
917 277 : }
918 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterConfigListener')) {
919 277 : $this->_lifecycleManager->addAfterConfigListener($bean);
920 277 : }
921 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterDefinitionListener')) {
922 277 : $this->_lifecycleManager->addAfterDefinitionListener($bean);
923 277 : }
924 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeCreateListener')) {
925 1 : $this->_lifecycleManager->addBeforeCreateListener($bean);
926 1 : }
927 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterCreateListener')) {
928 277 : $this->_lifecycleManager->addAfterCreateListener($bean);
929 277 : }
930 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeAssembleListener')) {
931 1 : $this->_lifecycleManager->addBeforeAssembleListener($bean);
932 1 : }
933 277 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterAssembleListener')) {
934 1 : $this->_lifecycleManager->addAfterAssembleListener($bean);
935 1 : }
936 277 : if ($rClass->implementsInterface('Ding\Aspect\IAspectProvider')) {
937 274 : $this->_aspectManager->registerAspectProvider($bean);
938 274 : }
939 277 : if ($rClass->implementsInterface('Ding\Aspect\IPointcutProvider')) {
940 197 : $this->_aspectManager->registerPointcutProvider($bean);
941 197 : }
942 277 : }
943 :
944 : /**
945 : * Called when a signal is caught.
946 : *
947 : * @param integer $signo
948 : *
949 : * @return void
950 : */
951 : public function signalHandler($signo)
952 : {
953 2 : $msg = "Caught Signal: $signo";
954 2 : $this->_logger->warn($msg);
955 2 : $this->eventDispatch('dingSignal', $signo);
956 2 : }
957 :
958 : /**
959 : * Called by php after set_error_handler()
960 : *
961 : * @param integer $type
962 : * @param string $message
963 : * @param string $file
964 : * @param integer $line
965 : *
966 : * @return true
967 : */
968 : public function errorHandler($type, $message, $file, $line)
969 : {
970 11 : $msg = "$message in $file:$line";
971 11 : if ($msg == $this->_lastErrorMessage) {
972 1 : return;
973 : }
974 11 : $this->_lastErrorMessage = $msg;
975 11 : $this->_logger->error($msg);
976 11 : $this->eventDispatch(
977 11 : 'dingError', new ErrorInfo($type, $message, $file, $line)
978 11 : );
979 11 : return true;
980 : }
981 :
982 : // @codeCoverageIgnoreStart
983 : /**
984 : * Called by the vm after register_shutdown_function()
985 : *
986 : * @return void
987 : */
988 : public function shutdownHandler()
989 : {
990 : $msg = "Shutting down";
991 : $this->eventDispatch('dingShutdown');
992 : }
993 : // @codeCoverageIgnoreEnd
994 :
995 : /**
996 : * (non-PHPdoc)
997 : * @see Ding\Container.IContainer::registerProperties()
998 : */
999 : public function registerProperties(array $properties)
1000 : {
1001 277 : foreach ($properties as $key => $value) {
1002 49 : if (strncmp($key, 'php.', 4) === 0) {
1003 2 : ini_set(substr($key, 4), $value);
1004 2 : }
1005 49 : $this->_properties['${' . $key . '}'] = $value;
1006 277 : }
1007 277 : }
1008 :
1009 : /**
1010 : * Constructor.
1011 : *
1012 : * @param array $options options.
1013 : *
1014 : * @return void
1015 : */
1016 : protected function __construct(array $options)
1017 : {
1018 : // Setup logger.
1019 277 : $this->_logger = \Logger::getLogger(get_class($this));
1020 277 : $this->_logDebugEnabled = $this->_logger->isDebugEnabled();
1021 277 : $soullessArray = array();
1022 277 : $this->_beanAliases = $soullessArray;
1023 277 : $this->_beanDefs = $soullessArray;
1024 277 : $this->_beans = $soullessArray;
1025 277 : $this->_shutdowners = $soullessArray;
1026 277 : $this->_resources = $soullessArray;
1027 277 : $this->_eventListeners = $soullessArray;
1028 277 : $this->_properties = $soullessArray;
1029 :
1030 : // Merge options with our defaults.
1031 277 : self::$_options = array_replace_recursive(self::$_options, $options);
1032 277 : $this->registerProperties(self::$_options['properties']);
1033 277 : $sapi = php_sapi_name();
1034 277 : if ($sapi == 'cgi' || $sapi == 'cli') {
1035 277 : $handler = array($this, 'signalHandler');
1036 277 : foreach ($this->_signals as $signal) {
1037 277 : pcntl_signal($signal, $handler);
1038 277 : }
1039 277 : pcntl_sigprocmask(SIG_UNBLOCK, $this->_signals);
1040 277 : }
1041 277 : set_error_handler(array($this, 'errorHandler'));
1042 277 : register_shutdown_function(array($this, 'shutdownHandler'));
1043 :
1044 277 : $this->_lifecycleManager = new BeanLifecycleManager;
1045 277 : $this->_dispatcherTemplate = new DispatcherImpl();
1046 277 : $this->_aspectManager = new AspectManager();
1047 277 : $this->_aspectManager->setCache(DummyCacheImpl::getInstance());
1048 277 : $this->_beanDefCache = DummyCacheImpl::getInstance();
1049 277 : $this->_beanCache = DummyCacheImpl::getInstance();
1050 277 : $this->registerBeanDefinitionProvider(new Core(self::$_options));
1051 277 : $this->_reflectionFactory = $this;
1052 277 : $this->_reflectionFactory = $this->getBean('dingReflectionFactory');
1053 277 : $this->_proxyFactory = $this->getBean('dingProxyFactory');
1054 277 : $this->_beanDefCache = $this->getBean('dingDefinitionsCache');
1055 277 : $this->_beanCache = $this->getBean('dingBeanCache');
1056 277 : $this->_lifecycleManager = $this->getBean('dingLifecycleManager');
1057 277 : $this->_aspectManager = $this->getBean('dingAspectManager');
1058 277 : $this->_dispatcherTemplate = $this->getBean('dingAspectCallDispatcher');
1059 :
1060 : // Set drivers
1061 277 : if (isset(self::$_options['bdef']['xml'])) {
1062 169 : $xmlDriver = $this->getBean('dingXmlBeanDefinitionProvider');
1063 169 : }
1064 277 : if (isset(self::$_options['bdef']['yaml'])) {
1065 38 : $yamlDriver = $this->getBean('dingYamlBeanDefinitionProvider');
1066 38 : }
1067 277 : $this->getBean('dingPropertiesDriver');
1068 277 : $this->getBean('dingMessageSourceDriver');
1069 277 : $this->getBean('dingMethodInjectionDriver');
1070 :
1071 : // All set, continue.
1072 277 : if (isset(self::$_options['bdef']['annotation'])) {
1073 112 : $this->getBean('dingAnnotationDiscovererDriver');
1074 112 : $this->getBean('dingAnnotationBeanDefinitionProvider');
1075 112 : $this->getBean('dingAnnotationValueDriver');
1076 112 : $this->getBean('dingAnnotationResourceDriver');
1077 112 : $this->getBean('dingAnnotationInitDestroyMethodDriver');
1078 112 : $this->getBean('dingAnnotationRequiredDriver');
1079 112 : $this->getBean('dingMvcAnnotationDriver');
1080 112 : }
1081 277 : $this->_lifecycleManager->afterConfig();
1082 273 : }
1083 : }
|